package de.openlaboratory.elib.controller;

import java.io.Serializable;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

import de.openlaboratory.elib.core.LogManager;
import de.openlaboratory.elib.database.hibernate.HibernateUtil;

public abstract class GenericDAOHibernate<T, PK extends Serializable> implements GenericDAO<T, PK>
{
	private Class<T> type;
	private Session session;
	private Transaction tx;

	private Session getSession()
	{
		return HibernateUtil.getSessionFactory().openSession();
	}

	@SuppressWarnings("unused")
	private void setSessionFactory()
	{
		HibernateUtil.getSessionFactory();
	}

	public GenericDAOHibernate(Class<T> type)
	{
		this.type = type;
	}

	@SuppressWarnings("unchecked")
	public PK create(T o)
	{
		LogManager.logMessage("GenericDAO.create [" + o.getClass().toString() + "]");
		
		Session s = getSession();

		s.beginTransaction();
		PK key = (PK) s.save(o);
		s.getTransaction().commit();
		
		return key;
	}

	@SuppressWarnings("unchecked")
	public T read(PK id)
	{
		return (T) getSession().get(type, id);
	}

	public void update(T o)
	{
		Session s = getSession();

		s.beginTransaction();
		s.update(o);
		s.getTransaction().commit();
	}

	public void delete(T o)
	{
		Session s = getSession();

		s.beginTransaction();
		s.delete(o);
		s.getTransaction().commit();
	}

	// second approach

	protected void startOperation() throws HibernateException
	{
		session = HibernateUtil.currentSession();
		tx = session.beginTransaction();
	}

	protected void handleException(HibernateException e) throws HibernateException
	{
		HibernateUtil.rollback(tx);
		throw e;
	}

	protected void saveOrUpdate(T obj)
	{
		try
		{
			startOperation();
			session.saveOrUpdate(obj);
			tx.commit();
		}
		catch (HibernateException e)
		{
			handleException(e);
		}
		finally
		{
			// HibernateUtil.close(session);
		}
	}

	protected void remove(T obj)
	{
		try
		{
			startOperation();
			session.delete(obj);
			tx.commit();
		}
		catch (HibernateException e)
		{
			handleException(e);
		}
		finally
		{
			// HibernateUtil.close(session);
		}
	}

	protected Object find(T o, Long id)
	{
		Object obj = null;
		try
		{
			startOperation();
			
			// session.load will only load proxy and not query the actual database
			obj = session.get(o.getClass(), id);
			tx.commit();
		}
		catch (HibernateException e)
		{
			handleException(e);
		}
		finally
		{
			HibernateUtil.currentSession().close();
			// // HibernateFactory.close(session);
		}
		return obj;
	}

	protected List<?> findAll(T o)
	{
		List<?> objects = null;
		try
		{
			LogManager.logMessage("Querying all entries from : " + o.getClass().getName());
			
			startOperation();
			Query query = session.createQuery("from " + o.getClass().getName());
			objects = query.list();
			tx.commit();
		}
		catch (HibernateException e)
		{
			handleException(e);
		}
		finally
		{
			HibernateUtil.currentSession().close();
		}
		return objects;
	}

}